<template>
  <div class="app-container">
    <div class="filter-container">
      <slot
        :operations="commonOperations"
        :on-submit="operationSubmit"
        :on-operation-click="operationClick"
      >
        <complex-operation
          ref="operation"
          :operations="commonOperations"
          @submit="operationSubmit"
          @operation-click="operationClick"
        />
      </slot>
    </div>
    <slot
      :list-query="listQuery"
      :total="total"
      :primary-key="primaryKey"
      :table-headers="tableHeaders"
      :list="list"
      :list-loading="listLoading"
      :on-selection-change="handleSelectionChange"
      :on-get-list="getList"
      :on-operation-click="operationClick"
    >
      <complex-table
        ref="table"
        :list-query="listQuery"
        :total="total"
        :primary-key="primaryKey"
        :table-headers="tableHeaders"
        :list="list"
        :list-loading="listLoading"
        @selection-change="handleSelectionChange"
        @get-list="getList"
        @operation-click="operationClick"
        @form-submit="handleFormSubmit"
        @form-cancel="handleFormCancel"
      />
    </slot>
    <el-dialog
      v-if="dialogFormVisible"
      width="70%"
      :title="textMap[dialogStatus]"
      :visible.sync="dialogFormVisible"
      :close-on-click-modal="false"
    >
      <slot
        v-if="!dialogFormNewVisible"
        name="form"
        :form-loading="formLoading"
        :info="info"
        :form-id="formId"
        :inputs="inputs"
        :operation="formOperation"
        :column="formColumn"
        :on-submit="handleFormSubmit"
        :on-cancel="handleFormCancel"
      >
        <complex-form
          ref="complex-form"
          v-loading="formLoading"
          :info="info"
          :form-id="formId"
          :inputs="inputs"
          :operation="formOperation"
          :column="formColumn"
          @submit="handleFormSubmit"
          @cancel="handleFormCancel"
        />
      </slot>
      <slot
        v-if="dialogFormNewVisible"
        name="form-new"
        :form-loading="formLoading"
        :info="info"
        :form-id="formId"
        :inputs="inputs"
        :operation="formOperation"
        :column="formColumn"
        :on-submit="handleFormSubmit"
        :on-cancel="handleFormCancel"
      >
        <complex-form
          ref="complex-form"
          v-loading="formLoading"
          :info="info"
          :form-id="formId"
          :inputs="inputs"
          :operation="formOperation"
          :column="formColumn"
          @submit="handleFormSubmit"
          @cancel="handleFormCancel"
        />
      </slot>
    </el-dialog>
  </div>
</template>

<script>
import {
  fetchList,
  fetchTableInfo,
  fetchInfo,
  editInfo,
  createInfo
} from '@/api/complex/table'
import waves from '@/directive/waves' // waves directive
import { mapGetters } from 'vuex'
import { parseTime } from '@/utils'
import ComplexOperation from '@/views/complex/operation'
import ComplexForm from '@/views/complex/form'
import ComplexTable from '@/views/complex/table'
import OperationClickHandler from '@/layout/mixin/OperationClickHandler'

export default {
  name: 'ComplexAssembly',
  components: { ComplexTable, ComplexOperation, ComplexForm },
  directives: { waves },
  filters: {
    parseTime(timestamp, format) {
      format = format || '{y}-{m}-{d} {h}:{i}'
      return parseTime(timestamp, format)
    }
  },
  mixins: [OperationClickHandler],
  data() {
    return {
      // [传入table组件] 列表信息
      list: [],
      // [传入table组件] 列表总数
      total: 0,
      // [传入table组件] 列表loading状态
      listLoading: false,
      // [用于fetchList接口传参] 列表查询参数
      listQuery: {
        page: 1,
        limit: this.pageSize
      },
      // [来自table组件] 被选中的列表
      checkList: [],
      // 窗口显示状态
      dialogFormVisible: false,
      // 新窗口的显示状态
      dialogFormNewVisible: false,
      // 弹窗状态 edit|create
      dialogStatus: '',
      // 弹窗标题 根据dialogStatus发生变化
      textMap: {
        edit: '编辑',
        create: '创建'
      },
      // 以字段名存储的inputs 用于每个字段的弹窗显示不同的内容
      inputMap: {},
      // [传入form组件] 表单loading状态
      formLoading: false,
      // [传入table组件] 表头字段列表
      tableHeaders: [],
      // [传入form组件] 表单ID
      formId: 0,
      // [传入form组件] 输入框信息列表
      inputs: [],
      // [传入form组件] 详情数据
      info: {},
      // [传入form组件] 操作
      formOperation: {},
      // [传入form组件] 列信息
      formColumn: {},
      // [传入operation组件] 公共操作列表
      commonOperations: [],
      // 数据库主键
      primaryKey: 'id',
      // [来自fetchTableInfo接口][用于获取列表数据]
      listUrl: '',
      // [来自fetchTableInfo接口][用于获取表单信息]
      inputUrl: '',
      // [来自fetchTableInfo接口][用于获取详情信息]
      infoUrl: '',
      // [来自fetchTableInfo接口][用于修改数据]
      editUrl: '',
      // [来自fetchTableInfo接口][用于新增数据]
      createUrl: '',
      // [来自fetchTableInfo接口][用于删除/批量删除数据]
      deleteUrl: '',
      // 用于轮询的url类型
      urlTypes: ['listUrl', 'inputUrl', 'infoUrl', 'editUrl', 'createUrl', 'deleteUrl']
    }
  },
  computed: {
    ...mapGetters(['pageSize', 'baseUrl'])
  },
  watch: {
    // 程序进来时执行 第一步 监听路由的变化 如果有参数则请求参数信息
    $route: {
      async handler(route) {
        const queryParams = route.meta.queryParams
        if (queryParams) {
          this.clearData()
          // 走第二步
          await this.getTableInfo(queryParams)
          // 走第三步
          await this.getList()
        }
      },
      immediate: true
    }
  },
  methods: {
    // 清除数据 当请求不同的页面的接口时需要把上次接口的数据清除
    clearData() {
      this.inputs = []
      this.listQuery = {
        page: 1,
        limit: parseInt(this.pageSize)
      }
    },
    // 第二步 请求表信息 包括 表头信息tableHeaders,公共操作commonOperations,urlTypes里面的url(url可被路由参数替换)
    getTableInfo(url) {
      return fetchTableInfo(url).then(response => {
        // 路由请求参数
        const query = this.$router.history.current.query
        // 表头信息
        this.tableHeaders = response.data.tableHeaders
        // 公共操作
        this.commonOperations = response.data.commonOperations
        // 公共url
        const commonUrls = response.data.commonUrls || response.data
        // 优先从路由获取url 其次从commonUrls获取
        this.urlTypes.map(urlType => {
          if (query[urlType]) {
            // 如果路由上有则用路由上的url
            this[urlType] = query[urlType]
          } else if (commonUrls[urlType]) {
            // 如果没有则用接口传来的url
            this[urlType] = commonUrls[urlType]
          }
        })

        // 没传createUrl默认取editUrl
        this.createUrl = this.createUrl || commonUrls.editUrl
        // 没传inputUrl inputs默认取tableHeaders
        if (this.inputUrl === undefined || this.inputUrl === null || this.inputUrl === '') {
          this.inputMap['_action_'] = this.tableHeaders
        }

        // 主键
        if (response.data.primaryKey) {
          this.primaryKey = response.data.primaryKey
        }
      }).catch(() => {
        this.listLoading = false
      })
    },
    // 第三步 获取列表信息
    getList() {
      // 500 毫秒没有返回值才加载loading
      const timerId = setTimeout(() => {
        this.listLoading = true
      }, 500)
      return fetchList(this.listUrl, this.listQuery).then(response => {
        this.list = response.data.list
        this.total = response.data.total
        this.listLoading = false
        clearTimeout(timerId)
      }).catch(() => {
        clearTimeout(timerId)
        this.listLoading = false
      })
    },
    // [edit|editNew调用] 获取详情信息
    getInfo(url, operation, inputs, column) {
      if (column.action === 'editNew' && operation.infoUrl === '') {
        this.showForm(inputs, operation, column)
        this.info = {}
        this.$emit('after-get-info', { response: {}, operation })
        return
      }
      return fetchInfo(url).then(response => {
        for (let i = 0; i < inputs.length; i++) {
          for (const key in response.data) {
            if (key === inputs[i].field) {
              if (response.data.hasOwnProperty(key)) {
                inputs[i].value = response.data[key]
              }
            }
          }
        }
        return { inputs, response }
      }).then(({ inputs, response }) => {
        this.showForm(inputs, operation, column)
        this.info = response.data
        this.$emit('after-get-info', { response, operation })
      })
    },
    // [响应table组件] 当列表被选中时
    handleSelectionChange(rows) {
      this.checkList = rows
    },
    // [edit|editNew|create调用] 显示表单输入弹窗
    showForm(inputs, operation, column) {
      this.inputs = inputs
      this.dialogFormVisible = true
      this.formOperation = operation
      this.formColumn = column
    },
    // [响应form组件] 当表单提交时
    handleFormSubmit(form, operation, id) {
      this.formLoading = true
      switch (operation.action) {
        case 'create':
          createInfo(this.editUrl, form).then(response => {
            this.$notify({
              title: 'success',
              type: 'success',
              message: response.msg,
              duration: 2000
            })

            this.getList()
            this.dialogFormVisible = false
            this.formId = 0
            this.formLoading = false
          }).catch(() => {
            this.formLoading = false
          })
          break

        case 'edit':
        case 'form':
          if (id <= 0) {
            this.$message.warning('ID 异常: id:' + id)
            return
          }
          editInfo(this.editUrl, id, form).then(response => {
            this.$notify({
              title: 'success',
              type: 'success',
              message: response.msg,
              duration: 2000
            })
            this.getList()
            this.dialogFormVisible = false
            this.formId = 0
            this.formLoading = false
          }).catch(() => {
            this.formLoading = false
          })
          break

        case 'editNew':
          // 这里ID已经在路由上了 无需再传ID
          editInfo(operation.editUrl, null, form).then(response => {
            this.$notify({
              title: 'success',
              type: 'success',
              message: response.msg,
              duration: 2000
            })
            this.getList()
            this.dialogFormVisible = false
            this.formId = 0
            this.formLoading = false
          }).catch(() => {
            this.formLoading = false
          })
          break

        default:
          this.formLoading = false
          this.$message.warning('不支持的action类型')
          break
      }
    },
    // [响应form组件] 当表单取消时
    handleFormCancel() {
      this.formId = 0
      this.dialogFormVisible = false
    },
    // [响应operation组件] 当点击搜索时 请求列表 传入筛选和搜索参数
    operationSubmit(query, operations) {
      this.listQuery = Object.assign({
        page: this.listQuery.page,
        limit: this.listQuery.limit
      }, query)
      this.listLoading = true
      this.getList()
      operations = null;
    },
    // [响应operation|table组件] 当操作的按钮点击时 找到对应的Handler并执行
    operationClick({ operation, row, column }) {
      const handler = operation.action + 'Handler'
      if (typeof this[handler] === 'function') {
        const rows = this.checkList
        if (!row && rows[0]) {
          row = rows[0]
        }
        this[handler]({ operation, rows, row, column })
      } else {
        this.$message.info(operation.action + '方法不存在')
      }
    }
  }
}
</script>
